var Reg = {
  PERIPH_BASE: 0x40000000,
  APB1PERIPH_BASE: 0x40000000,
  APB2PERIPH_BASE: 0x40000000 + 0x10000,
  GPIOA_BASE: 0x40000000 + 0x10000 + 0x0800,
  GPIOB_BASE: 0x40000000 + 0x10000 + 0x0C00,
  GPIOC_BASE: 0x40000000 + 0x10000 + 0x1000,
  GPIOD_BASE: 0x40000000 + 0x10000 + 0x1400,
  GPIOE_BASE: 0x40000000 + 0x10000 + 0x1800,
  GPIOF_BASE: 0x40000000 + 0x10000 + 0x1C00,
  GPIOG_BASE: 0x40000000 + 0x10000 + 0x2000,
  DAC_BASE: 0x40000000 + 0x7400
};

var State = {Input:0, Output10Mhz: 1, Output2Mhz: 2, Output50Mhz: 3,
  InputAnalog: 0<<2, InputFloating: 1<<2, InputPull: 2<<2,
  OutputPushPull: 0<<2, OutputOpenDrain: 1<<2, OutputFunctionPushPull: 2<<2,
  OutputFunctionOpenDrain: 3<<2};

function SetState(baseAddr, pin, state)
{
  var dwAddr;

  if ( pin < 8 )
    dwAddr = baseAddr + 0;	// CRL
  else
  {
    dwAddr = baseAddr + 4;	// CRH
    pin &= 7;
  }

  var dwMask = 0xf << (pin*4);
  var dwBits = state << (pin*4);

  INTERFACE.process( () => BIOS.biosMemMask32(dwAddr, dwMask, dwBits) );
}

function DACOn()
{
  INTERFACE.process( () => BIOS.biosMemMask32(Reg.DAC_BASE, 1, 1) );
}

function DACOff()
{
  INTERFACE.process( () => BIOS.biosMemMask32(Reg.DAC_BASE, 1, 0) );
}

function GetPA4()
{
  var pin = 4;
  dwAddr = Reg.GPIOA_BASE;

  INTERFACE.process( () => BIOS.biosMemRead32(dwAddr).then(x => console.log([x.toString(16), (x >> pin*4) & 15 ])) );
}

function SetPA4Input()
{
  SetState(Reg.GPIOA_BASE, 4, State.InputFloating);
}

function SetPA4AF()
{
  SetState(Reg.GPIOA_BASE, 4, State.OutputFunctionPushPull);
}

function SetDigital()
{
  INTERFACE.process( () => BIOS.biosMemMask32(0x40010800, 0xf0000, 0x40000) );
  INTERFACE.process( () => BIOS.biosMemWrite32(0x40001400, 0x84) );
  INTERFACE.process( () => BIOS.biosMemWrite32(0x40007400, 0x0) );
  INTERFACE.process( () => BIOS.biosMemWrite32(0x40000800, 0x80) );
  INTERFACE.process( () => BIOS.biosMemMask32(0x40010C00, 0xf000000, 0x3000000) );
}

function SetHigh()
{
  INTERFACE.process( () => BIOS.biosMemWrite32(0x40010C10, 1<<6) );
}

function SetLow()
{
  INTERFACE.process( () => BIOS.biosMemWrite32(0x40010C14, 1<<6) );
}

function Burst()
{
  var buf = ledtest();

  var toBin = (x) => 
  {
    var s = "";
    s+= x & 1 ? "1" : "0"; x >>= 1;
    s+= x & 1 ? "1" : "0"; x >>= 1;
    s+= x & 1 ? "1" : "0"; x >>= 1;
    s+= x & 1 ? "1" : "0"; x >>= 1;

    s+= x & 1 ? "1" : "0"; x >>= 1;
    s+= x & 1 ? "1" : "0"; x >>= 1;
    s+= x & 1 ? "1" : "0"; x >>= 1;
    s+= x & 1 ? "1" : "0"; x >>= 1;
    return s;
  }

//console.log(buf.map(v => toBin(v)).join(" "));
  var len = buf.length;
  var bufferPtr = 0;
  INTERFACE.process( () => Promise.resolve() 
    .then( () => BIOS.biosMemGetBufferPtr() )
    .then( (ptr) => bufferPtr = ptr )
    .then( () => BIOS.biosMemBulk(bufferPtr, buf) )
    .then( () => BIOS.rpcCall('MEM::TestBurst(0x'+bufferPtr.toString(16)+', '+len+');') )
  );
}

var luta=[
0x92,0x49,0x24,0x92,0x49,0x26,0x92,0x49,0x34,0x92,0x49,0x36,0x92,0x49,0xA4,0x92,0x49,0xA6,0x92,0x49,0xB4,0x92,0x49,0xB6,0x92,0x4D,0x24,0x92,0x4D,0x26,0x92,0x4D,0x34,0x92,0x4D,0x36,0x92,0x4D,0xA4,0x92,0x4D,0xA6,0x92,0x4D,0xB4,0x92,0x4D,0xB6,0x92,0x69,0x24,0x92,0x69,0x26,0x92,0x69,0x34,0x92,0x69,0x36,0x92,0x69,0xA4,0x92,0x69,0xA6,0x92,0x69,0xB4,0x92,0x69,0xB6,0x92,0x6D,0x24,0x92,0x6D,0x26,0x92,0x6D,0x34,0x92,0x6D,0x36,0x92,0x6D,0xA4,0x92,0x6D,0xA6,0x92,0x6D,0xB4,0x92,0x6D,0xB6,0x93,0x49,0x24,0x93,0x49,0x26,0x93,0x49,0x34,0x93,0x49,0x36,0x93,0x49,0xA4,0x93,0x49,0xA6,0x93,0x49,0xB4,0x93,0x49,0xB6,0x93,0x4D,0x24,0x93,0x4D,0x26,0x93,0x4D,0x34,0x93,0x4D,0x36,0x93,0x4D,0xA4,0x93,0x4D,0xA6,0x93,0x4D,0xB4,0x93,0x4D,0xB6,0x93,0x69,0x24,0x93,0x69,0x26,0x93,0x69,0x34,0x93,0x69,0x36,0x93,0x69,0xA4,0x93,0x69,0xA6,0x93,0x69,0xB4,0x93,0x69,0xB6,0x93,0x6D,0x24,0x93,0x6D,0x26,0x93,0x6D,0x34,0x93,0x6D,0x36,0x93,0x6D,0xA4,0x93,0x6D,0xA6,0x93,0x6D,0xB4,0x93,0x6D,0xB6,0x9A,0x49,0x24,0x9A,0x49,0x26,0x9A,0x49,0x34,0x9A,0x49,0x36,0x9A,0x49,0xA4,0x9A,0x49,0xA6,0x9A,0x49,0xB4,0x9A,0x49,0xB6,0x9A,0x4D,0x24,0x9A,0x4D,0x26,0x9A,0x4D,0x34,0x9A,0x4D,0x36,0x9A,0x4D,0xA4,0x9A,0x4D,0xA6,0x9A,0x4D,0xB4,0x9A,0x4D,0xB6,0x9A,0x69,0x24,0x9A,0x69,0x26,0x9A,0x69,0x34,0x9A,0x69,0x36,0x9A,0x69,0xA4,0x9A,0x69,
0xA6,0x9A,0x69,0xB4,0x9A,0x69,0xB6,0x9A,0x6D,0x24,0x9A,0x6D,0x26,0x9A,0x6D,0x34,0x9A,0x6D,0x36,0x9A,0x6D,0xA4,0x9A,0x6D,0xA6,0x9A,0x6D,0xB4,0x9A,0x6D,0xB6,0x9B,0x49,0x24,0x9B,0x49,0x26,0x9B,0x49,0x34,0x9B,0x49,0x36,0x9B,0x49,0xA4,0x9B,0x49,0xA6,0x9B,0x49,0xB4,0x9B,0x49,0xB6,0x9B,0x4D,0x24,0x9B,0x4D,0x26,0x9B,0x4D,0x34,0x9B,0x4D,0x36,0x9B,0x4D,0xA4,0x9B,0x4D,0xA6,0x9B,0x4D,0xB4,0x9B,0x4D,0xB6,0x9B,0x69,0x24,0x9B,0x69,0x26,0x9B,0x69,0x34,0x9B,0x69,0x36,0x9B,0x69,0xA4,0x9B,0x69,0xA6,0x9B,0x69,0xB4,0x9B,0x69,0xB6,0x9B,0x6D,0x24,0x9B,0x6D,0x26,0x9B,0x6D,0x34,0x9B,0x6D,0x36,0x9B,0x6D,0xA4,0x9B,0x6D,0xA6,0x9B,0x6D,0xB4,0x9B,0x6D,0xB6,0xD2,0x49,0x24,0xD2,0x49,0x26,0xD2,0x49,0x34,0xD2,0x49,0x36,0xD2,0x49,0xA4,0xD2,0x49,0xA6,0xD2,0x49,0xB4,0xD2,0x49,0xB6,0xD2,0x4D,0x24,0xD2,0x4D,0x26,0xD2,0x4D,0x34,0xD2,0x4D,0x36,0xD2,0x4D,0xA4,0xD2,0x4D,0xA6,0xD2,0x4D,0xB4,0xD2,0x4D,0xB6,0xD2,0x69,0x24,0xD2,0x69,0x26,0xD2,0x69,0x34,0xD2,0x69,0x36,0xD2,0x69,0xA4,0xD2,0x69,0xA6,0xD2,0x69,0xB4,0xD2,0x69,0xB6,0xD2,0x6D,0x24,0xD2,0x6D,0x26,0xD2,0x6D,0x34,0xD2,0x6D,0x36,0xD2,0x6D,0xA4,0xD2,0x6D,0xA6,0xD2,0x6D,0xB4,0xD2,0x6D,0xB6,0xD3,0x49,0x24,0xD3,0x49,0x26,0xD3,0x49,0x34,0xD3,0x49,0x36,0xD3,0x49,0xA4,0xD3,0x49,0xA6,0xD3,0x49,0xB4,0xD3,0x49,0xB6,0xD3,0x4D,0x24,0xD3,0x4D,0x26,0xD3,0x4D,0x34,0xD3,
0x4D,0x36,0xD3,0x4D,0xA4,0xD3,0x4D,0xA6,0xD3,0x4D,0xB4,0xD3,0x4D,0xB6,0xD3,0x69,0x24,0xD3,0x69,0x26,0xD3,0x69,0x34,0xD3,0x69,0x36,0xD3,0x69,0xA4,0xD3,0x69,0xA6,0xD3,0x69,0xB4,0xD3,0x69,0xB6,0xD3,0x6D,0x24,0xD3,0x6D,0x26,0xD3,0x6D,0x34,0xD3,0x6D,0x36,0xD3,0x6D,0xA4,0xD3,0x6D,0xA6,0xD3,0x6D,0xB4,0xD3,0x6D,0xB6,0xDA,0x49,0x24,0xDA,0x49,0x26,0xDA,0x49,0x34,0xDA,0x49,0x36,0xDA,0x49,0xA4,0xDA,0x49,0xA6,0xDA,0x49,0xB4,0xDA,0x49,0xB6,0xDA,0x4D,0x24,0xDA,0x4D,0x26,0xDA,0x4D,0x34,0xDA,0x4D,0x36,0xDA,0x4D,0xA4,0xDA,0x4D,0xA6,0xDA,0x4D,0xB4,0xDA,0x4D,0xB6,0xDA,0x69,0x24,0xDA,0x69,0x26,0xDA,0x69,0x34,0xDA,0x69,0x36,0xDA,0x69,0xA4,0xDA,0x69,0xA6,0xDA,0x69,0xB4,0xDA,0x69,0xB6,0xDA,0x6D,0x24,0xDA,0x6D,0x26,0xDA,0x6D,0x34,0xDA,0x6D,0x36,0xDA,0x6D,0xA4,0xDA,0x6D,0xA6,0xDA,0x6D,0xB4,0xDA,0x6D,0xB6,0xDB,0x49,0x24,0xDB,0x49,0x26,0xDB,0x49,0x34,0xDB,0x49,0x36,0xDB,0x49,0xA4,0xDB,0x49,0xA6,0xDB,0x49,0xB4,0xDB,0x49,0xB6,0xDB,0x4D,0x24,0xDB,0x4D,0x26,0xDB,0x4D,0x34,0xDB,0x4D,0x36,0xDB,0x4D,0xA4,0xDB,0x4D,0xA6,0xDB,0x4D,0xB4,0xDB,0x4D,0xB6,0xDB,0x69,0x24,0xDB,0x69,0x26,0xDB,0x69,0x34,0xDB,0x69,0x36,0xDB,0x69,0xA4,0xDB,0x69,0xA6,0xDB,0x69,0xB4,0xDB,0x69,0xB6,0xDB,0x6D,0x24,0xDB,0x6D,0x26,0xDB,0x6D,0x34,0xDB,0x6D,0x36,0xDB,0x6D,0xA4,0xDB,0x6D,0xA6,0xDB,0x6D,0xB4,0xDB,0x6D,0xB6];

function lutaa(v)
{
  var out = 0;
  v = luta[v];
  if (v&1) out |= 128;
  if (v&2) out |= 64;
  if (v&4) out |= 32;
  if (v&8) out |= 16;
  if (v&16) out |= 8;
  if (v&32) out |= 4;
  if (v&64) out |= 2;
  if (v&128) out |= 1;
  return out;
}
function lut(i)
{
  i = Math.floor(i);
  if (i<0) i=0;
  if (i>255) i=255;
  return [lutaa(i*3), lutaa(i*3+1), lutaa(i*3+2)];
}

function rgbbuf(g, r, b)
{
  return [].concat(lut(g), lut(r), lut(b));
}

function ledtest()
{
  var total = [0];
  var t = (new Date).getTime()/2000;
  for (var i=0; i<24; i++)
  {
    t += 0.1;
    var r = Math.floor(128 + Math.cos(t)*127);
    var g = Math.floor(128 + Math.cos(t*1.3)*127);
    var b = Math.floor(128 + Math.cos(t*2.7)*127);
    var buf = rgbbuf(r/7, g/7, b/7);
    total = total.concat(buf);
  }
  total.push(0);
  return total;
}
